home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1996 / MacHack 1996.toast / Hacks / Hacks ’92 / DylanTalk / DylanTalk Source / Speech.c < prev   
Encoding:
C/C++ Source or Header  |  1992-06-14  |  5.9 KB  |  248 lines  |  [TEXT/MPS ]

  1. #include <Types.h>
  2. #include <Memory.h>
  3. #include <Resources.h>
  4. #include <Sound.h>
  5. #include <SysEqu.h>
  6.  
  7. #include "DylanTalk.h"
  8.  
  9.  
  10. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  11. pascal void SpeakStringSounds(register DylanTalkGlobalPtr globals)
  12. {
  13.     register Ptr    text = globals->firstDialogString;
  14.     Handle            speechHandle;
  15.     Boolean            done = false;
  16.     short            i = 0;
  17.     short            lastWordStart = -1;
  18.     short            numWords = 0;
  19.     short            runStartOffset;
  20.     OSErr            err;
  21.     Str255            word;
  22.  
  23.     if ( globals->dylanSndChannel != 0L)                        // check if we already have a channel
  24.         QuietChannel(globals->dylanSndChannel);
  25.     else
  26.     {
  27.         if (err = SndNewChannel(&(globals->dylanSndChannel), sampledSynth, initNoInterp, nil))
  28.             return;
  29.     }
  30.     
  31.     if (globals->wordQueue != nil)
  32.         FreeQueue(globals);
  33.     globals->wordQueue = (WordQueuePtr) NewPtrSysClear(1024L);    // 1k = 256 handles = 256 word max
  34.     if (MemError()) return;
  35.     
  36.     // now we have a channel and queue memory. We loop thru the string sending off words
  37.     // to be played in our channel.
  38.     
  39.     // First, convert the string to all uppercase
  40.     
  41.     ConvertStringToUpperCase(text);
  42.     
  43.     i = 0;
  44.     while (FindCharacterRun(text, i, &word, &runStartOffset)) {
  45.         i += runStartOffset + word[0];                            // Set up offset for next time through the loop
  46.         speechHandle = PlayWord(globals->dylanSndChannel, word, globals->personalityFile);
  47.         if (speechHandle != 0) {
  48.             ((globals->wordQueue)->aWord)[numWords++] = speechHandle;
  49.             ((globals->wordQueue)->aWord)[numWords] = nil;
  50.         }
  51.     }
  52. }
  53. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  54. pascal void KillStringSounds(register DylanTalkGlobalPtr globals)
  55. {
  56.     if (globals->dylanSndChannel != 0L)
  57.     {
  58.         KillChannel( globals->dylanSndChannel, globals->playingControlSound );
  59.         globals->playingControlSound = false;
  60.         globals->dylanSndChannel = nil;
  61.     }
  62.     
  63.     FreeQueue(globals);
  64. }
  65.  
  66. void FreeQueue(register DylanTalkGlobalPtr globals)
  67. {
  68.     register WordQueuePtr    wordQueue = globals->wordQueue;
  69.     Handle                    stringSound;
  70.     short                    i;
  71.     
  72.     if (wordQueue != 0L) {
  73.         for (i = 0; i < 256; ++i) {
  74.             stringSound = (wordQueue->aWord)[i];
  75.             if (stringSound != nil)
  76.                 ReleaseResource(stringSound);
  77.         }
  78.         DisposPtr((Ptr) wordQueue);
  79.         globals->wordQueue = nil;
  80.     }
  81. }
  82.  
  83. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  84. Handle GetSoundResourceForWord(ConstStr255Param word)
  85. {
  86.     Handle soundResource;
  87.     
  88.     soundResource = Get1NamedResource('snd ', (ConstStr255Param) word);
  89.     if ( soundResource == 0L)
  90.     {
  91.         soundResource = Get1Resource('snd ',word[1]+200-'A');
  92.         if ( soundResource == 0L )
  93.         {
  94.             soundResource = Get1Resource('snd ', 0);
  95.         }
  96.     }
  97.     
  98.     return soundResource;
  99. }
  100.  
  101. OSErr PlaySound(Handle theSound,SndChannelPtr channel )
  102. {
  103.     OSErr    err = noErr;
  104.     
  105.     if (theSound == 0L)
  106.         err = ResError();
  107.     else
  108.     {
  109.         HLock(theSound);
  110.         AddSound(theSound, channel);
  111.     }
  112.     
  113.     return err;
  114. }
  115.  
  116. Boolean CheckForNumber(ConstStr255Param word)
  117. {
  118.     Boolean hasNumber = false;
  119.     short    i;
  120.     
  121.     for (i=1; (i <= word[0]) && (!hasNumber); i++)
  122.     {
  123.         if ((word[i] <= '9') && ( word[i] >= '0'))
  124.         {
  125.             hasNumber = true;
  126.         }
  127.     }
  128.     return hasNumber;
  129. }
  130.  
  131. Handle PlayWord(SndChannelPtr channel,  ConstStr255Param word, short refNum)
  132. {
  133.     OSErr            err = 0;
  134.     Handle            soundResource;
  135.     short            oldRef;
  136.     long             num;
  137.     
  138.     if (channel != 0L)
  139.     {
  140.         oldRef = CurResFile();
  141.         UseResFile(refNum);
  142.         
  143.         soundResource = GetSoundResourceForWord(word);
  144.         if (soundResource == nil) {
  145.             if (CheckForNumber(word))
  146.             {
  147.                 num = StringToNumber(word);
  148.                      if  ( num < 10 ) num = 0;
  149.                 else if  ( num < 100 ) num = 1; 
  150.                 else if  ( num < 1000 ) num = 2; 
  151.                 else num = 3; 
  152.                 
  153.                 soundResource = GetResource('snd ',226+num);
  154.             }
  155.         }
  156.         err = PlaySound(soundResource, channel);
  157.         UseResFile(oldRef);
  158.     }
  159.     if (err)
  160.         return 0L;
  161.     else
  162.         return soundResource;
  163. }
  164.  
  165.  
  166. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  167. void AddSound(Handle sndHandle,SndChannelPtr channel)
  168. {
  169.     SndCommand    theCmd;
  170.     long        offset;
  171.     OSErr        err;
  172.     
  173.     offset = GetBufferOffset(sndHandle);
  174.     theCmd.cmd = bufferCmd;
  175.     theCmd.param1 = 0;
  176.     theCmd.param2 = (long) *sndHandle + offset;
  177.     
  178.     err = SndDoCommand(channel, &theCmd, true);
  179. }
  180.  
  181. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  182. long GetBufferOffset(Handle sndHandle)
  183. {
  184.     short        synths;
  185.     short        howManyCmds;
  186.     Ptr           cruisePtr;
  187.     long          sndDataOffset;
  188.  
  189.     sndDataOffset = 0;
  190.     cruisePtr = *sndHandle;
  191.     if (cruisePtr != nil) {
  192.         if ( ((Snd1HdrPtr)cruisePtr)->format == firstSoundFormat ) {
  193.             synths = ((Snd1HdrPtr)cruisePtr)->numSynths;
  194.             cruisePtr += sizeof(Snd1Header) + (sizeof(SynthInfo) * synths);
  195.         }
  196.         else
  197.             cruisePtr += sizeof(Snd2Header);
  198.         howManyCmds = *((short *)cruisePtr);        // pointing at number of cmds 
  199.         cruisePtr += sizeof(howManyCmds);
  200.  
  201.         // cruisePtr is now at the first sound command 
  202.         // cruise all commands and find a soundCmd or bufferCmd 
  203.         do {
  204.             switch (((SndCmdPtr)cruisePtr)->cmd) {
  205.             
  206.                 case (soundCmd | dataOffsetFlag):
  207.                 case (bufferCmd | dataOffsetFlag):
  208.                     sndDataOffset = ((SndCmdPtr)cruisePtr)->param2;
  209.                     howManyCmds = 0;                // done, get out of loop 
  210.                     break;
  211.  
  212.                 default:                            // catch any other type of cmd 
  213.                     cruisePtr += sizeof(SndCommand);
  214.                     howManyCmds -= 1;
  215.                     break;
  216.             }
  217.         } while (howManyCmds >= 1);                    // done with all the commands 
  218.     }
  219.     return(sndDataOffset);
  220. }
  221. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  222. void QuietChannel(SndChannelPtr channel)
  223. {
  224.     OSErr            err;
  225.     SndCommand        theCmd;
  226.     
  227.     theCmd.cmd = flushCmd;
  228.     err = SndDoImmediate(channel, &theCmd);
  229.     theCmd.cmd = quietCmd;
  230.     err = SndDoImmediate(channel, &theCmd);
  231. }
  232.  
  233. void KillChannel( SndChannelPtr channel, Boolean waitForSoundToFinish )
  234. {
  235.     OSErr            err;
  236.     SCStatus        status;
  237.     
  238.     // If we’re playing a button title, wait for the sound to finish before
  239.     // disposing of the sound channel.
  240.     
  241.     if (waitForSoundToFinish) {
  242.         do {
  243.             err = SndChannelStatus(channel, sizeof(status), &status);
  244.         } while ((err == noErr) && (status.scChannelBusy)); 
  245.         
  246.     }
  247.     err = SndDisposeChannel(channel, true);
  248. }